package org.dim.oa.utils;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.util.*;

@Slf4j
public class FileUtil {
    //路径分隔符
    public static final String SEPARATOR = "/";
    //Point
    public static final String POINT = ".";

    //文件名称Key
    public static final String FILENAME = "filename";
    //文件最大的大小
    public static int MAX_FILE_SIZE = 262144000;

    //直接显示的附件类型

    //最多5个
//    public static final Map<String, String> EXT_MAPS1 =ImmutableMap.of("png","image/png",
//            "gif","image/gif","bmp","image/bmp", "ico","image/x-ico","jpeg","image/jpeg");
//    public static final Map<String, String> EXT_MAPS = new HashMap<String, String>() {{
//        put("png","image/png");
//        put("gif","image/gif");
//        put("bmp","image/bmp");
//        put("ico","image/x-ico");
//        put("jpeg","image/jpeg");
//        put("jpg","image/jpeg");
//        put("svg","image/svg+xml");
//        // 压缩文件
//        put("zip","application/zip");
//        put("rar","application/x-rar");
//        // doc
//        put("pdf","application/pdf");
//        put("ppt","application/vnd.ms-powerpoint");
//        put("xls","application/vnd.ms-excel");
//        put("xlsx","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
//        put("pptx","application/vnd.openxmlformats-officedocument.presentationml.presentation");
//        put("doc","application/wps-office.doc");
//        put("docx","application/vnd.openxmlformats-officedocument.wordprocessingml.document");
//        put("txt","text/plain");
//        put("html","text/html");
//        //音频
//        put("mp4","video/mp4");
//        put("flv","video/x-flv");
//    }

    public static final Map<String, String> EXT_MAPS = new HashMap<String, String>() {{
        put("png","png");
        put("gif","gif");
        put("bmp","bmp");
        put("ico","x-ico");
        put("jpeg","jpeg");
        put("jpg","jpeg");
        put("svg","svg");
        // 压缩文件
        put("zip","zip");
        put("rar","rar");
        // doc
        put("pdf","pdf");
        put("ppt","ppt");
        put("xls","xls");
        put("xlsx","xlsx");
        put("pptx","pptx");
        put("doc","doc");
        put("docx","docx");
        put("txt","txt");
        put("html","html");
        //音频
        put("mp4","mp4");
        put("flv","flv");
    }
};

    /**
     * 文件下载
     * @return
     */

    /**
     * 将byte[]类型的数据，写入到输出流中
     *
     * @param out       输出流
     * @param data      希望写入的数据
     * @param cacheSize 写入数据是循环读取写入的，此为每次读取的大小，单位字节，建议为4096，即4k
     */

    public static void writeBytesToOut(OutputStream out, byte[] data, int cacheSize) throws IOException {
        int surplus = data.length % cacheSize;
        int count = surplus == 0 ? data.length / cacheSize : data.length / cacheSize + 1;
        for (int i = 0; i < count; i++) {
            if (i == count - 1 && surplus != 0) {
                out.write(data, i * cacheSize, surplus);
                continue;
            }
            out.write(data, i * cacheSize, cacheSize);
        }
    }
    /**
     * 字符转数字字符串
     * @return
     */

    public static final String strToNumber(String fileName) {
        StringBuilder sb = new StringBuilder();
        for (Character c:fileName.toCharArray()) {
            Integer integer = Integer.valueOf(c);
            sb.append(integer);
        }
        return sb.toString();
    }
    /**
     * 转换路径中的 '\' 为 '/' <br>
     * 并把文件后缀转为小写
     *
     * @param path 路径
     * @return
     */

    public static String toLocal(String path) {
        if (StringUtils.isNotBlank(path)) {
            path = path.replaceAll("\\\\", SEPARATOR);
            if (path.contains(POINT)) {
                String pre = path.substring(0, path.lastIndexOf(POINT) + 1);
                String suffix = path.substring(path.lastIndexOf(POINT) + 1).toLowerCase();
                path = pre + suffix;
            }
        }
        return path;
    }

    public static final String generateUniqueFileName(String fileName) {
       return  DateUtil.getTimeStamp(fileName);
    }

    /**
     * 根据文件名获取文件类型
     */

    public static String getFileType(String filename) {
       return EXT_MAPS.getOrDefault(getFilenameSuffix(filename),"application/octet-stream");
    }

    /**
     * 获得前缀
     */

    public static String getFilenamePrefix1(String fileName) {
        if (StringUtils.isBlank(fileName)) {
            return "";
        }
        int lastIndexOf = fileName.lastIndexOf('.');
        return lastIndexOf == -1 ? fileName : fileName.substring(0, lastIndexOf);
    }

    //获取文件后缀名，不包含.
    public static String getFilenameSuffiox1(String fileName) {
        if (StringUtils.isBlank(fileName)) {
            return "";
        }
        int lastIndexOf = fileName.lastIndexOf('.');
        return lastIndexOf == -1 ? "" : fileName.substring(lastIndexOf + 1);
    }

    /**
     * 获取文件名称的后缀
     *
     * @param filename 文件名 或 文件路径
     * @return 文件后缀
     */

    public static String getFilenameSuffix(String filename) {
        String suffix = null;
        String originalFilename = filename;
        if (StringUtils.isNotBlank(filename)) {
            if (filename.contains(SEPARATOR)) {
                filename = filename.substring(filename.lastIndexOf(SEPARATOR) + 1);
            }
            if (filename.contains(POINT)) {
                suffix = filename.substring(filename.lastIndexOf(POINT) + 1);
            } else {
                if (log.isErrorEnabled()) {
                    log.info("filename error without suffix :{}", originalFilename);
                }
            }
        }
        return suffix;
    }
    /**
     * 获取文件前缀
     */

    public static String getFilenamePre(String filename) {

             return filename.substring(0,filename.lastIndexOf('.'));
    }

    /**
     * 创建文件夹
     * @param filepath
     */

    public static void mkdirs(String filepath) {
        File file = new File(filepath);
        if (!file.exists()) {
            if (file.mkdirs()) {
                log.info("makedir success, dir path{}", filepath);
            } else {
                log.error("makedir error, dir path{}", filepath);
            }
        }
    }

    /**
     * 根据文件路径获取文件名字
     * @param filepath
     * @return
     */

    public static String getFileName(String filepath) {
        filepath = filepath.replace("\\","/");
        int lastSeparator = filepath.lastIndexOf("/");
        if (lastSeparator != -1) {
            return filepath.substring(lastSeparator + 1);
        } else {
            throw new RuntimeException("can not find filename [filepath] :" + filepath);
        }
    }

    /**
     * 根据文件路径获取文件目录
     * @param filepath
     * @return
     */

    public static String getFileDir(String filepath) {
        filepath = filepath.replace("\\","/");
        int lastSeparator = filepath.lastIndexOf("/");
        if (lastSeparator != -1) {
            return filepath.substring(0, lastSeparator);
        } else {
            throw new RuntimeException("can not find filepath " + filepath);
        }
    }

    /**
     * 根据文件路径复制文件
     * @param sourcePath
     * @param targetPath
     */

    public static void copyFile(String sourcePath, String targetPath) throws IOException {
        // 创建文件夹
        String targetDir = getFileDir(targetPath);
        mkdirs(targetDir);
        // 创建目标文件
        File targetFile = new File(targetPath);
        if (!targetFile.exists()) {
            targetFile.createNewFile();
        }
        copyFileInStream(new File(sourcePath), targetFile);
    }

    /**
     * 复制文件
     * @param sourceFile
     * @param targetFile
     */

    public static void copyFileInStream(File sourceFile, File targetFile) {
        InputStream input = null;
        OutputStream output = null;
        try {
            input = new FileInputStream(sourceFile);
            output = new FileOutputStream(targetFile);
            byte[] buf = new byte[1024];
            int bytesRead;
            while ((bytesRead = input.read(buf)) != -1) {
                output.write(buf, 0, bytesRead);
            }
        } catch (IOException e) {
            log.error("" + e);
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    log.error("close stream error");
                }
            }
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    log.error("close stream error");
                }
            }
        }
    }

    /**
     * 将文件输入流写入指定路径
     * @param inputStream
     * @param targetpath
     */

    public static void writeInputStreamToLocal(InputStream inputStream, String targetpath) {
        FileOutputStream fileOutputStream = null;
        // 创建文件目录
        String filedir = getFileDir(targetpath);
        mkdirs(filedir);
        try {
            fileOutputStream = new FileOutputStream(targetpath);
//            int size = inputStream.available();
//            byte[] filebytes = new byte[size];
//            fileOutputStream.write(filebytes);
            int index;
            byte[] filebytes = new byte[1024];
            while ((index = inputStream.read(filebytes)) != -1) {
                fileOutputStream.write(filebytes, 0, index);
                fileOutputStream.flush();
            }
        } catch (IOException e) {
            log.error("" + e);
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    log.error("close stream error");
                }
            }
        }
    }

    /**
     * 根据文件路径获取文件byte流
     * @param filePath
     * @return
     */

    public static byte[] getBytes(String filePath) {
        FileInputStream fis = null;
        ByteArrayOutputStream bos = null;
        byte[] buffer = null;
        try {
            File file = new File(filePath);
            fis = new FileInputStream(file);
            bos = new ByteArrayOutputStream(1024);
            byte[] b = new byte[1024];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            buffer = bos.toByteArray();
        } catch (FileNotFoundException e) {
            log.error("" + e);
        } catch (IOException e) {
            log.error("" + e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    log.error("close stream error");
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    log.error("close stream error");
                }
            }
        }
        return buffer;
    }

    /**
     * 将byte文件流写入文件
     * @param fbyte
     * @param filepath
     */

    public static void writeByteToFile(byte[] fbyte, String filepath) {
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        // 创建文件夹
        String dirpath = getFileDir(filepath);
        mkdirs(dirpath);
        File file = new File(filepath);
        try {
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(fbyte);
        } catch (IOException e) {
            log.error("" + e);
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    log.error("close stream error");
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    log.error("close stream error");
                }
            }
        }
    }

    public static void getFilePaths(String filepath, List<String> pathList) throws FileNotFoundException {
        File file = new File(filepath);
        if (!file.exists()) {
            throw new FileNotFoundException("not find file " + filepath);
        }
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
                getFilePaths(f.getAbsolutePath(), pathList);
            }
        } else {
            pathList.add(filepath);
        }
    }

    public static void deleteFile(String filepath) {
        File file = new File(filepath);
        if (file.exists() && file.isFile()) {
            file.delete();
        }
    }

    public static String getDestPath(String configPath) {
        String curDate = DateUtil.formatDatetoString(new Date(), DateUtil.YYYYMMDD);
        return configPath + "/" + curDate;
    }

    public static boolean renameFile(File toBeRenamed, String toFileNewName) {
        //检查要重命名的文件是否存在，是否是文件
        if (!toBeRenamed.exists() || toBeRenamed.isDirectory()) {
            log.info("File does not exist: " + toBeRenamed.getName());
            return false;
        }
        String parentDir = toBeRenamed.getParent();
        File newFile = new File(parentDir + File.separatorChar + toFileNewName);
        // 重命名的新文件若存在，直接删除
        if (newFile.exists() && newFile.isFile()) {
            log.info("delete duplicate file{}", newFile.getAbsolutePath());
            newFile.delete();
        }
        //修改文件名
        return toBeRenamed.renameTo(newFile);
    }

    /**
     * byte 数组写入文件
     * @param bytes
     * @param offset
     * @param file
     */

    public static void mergeRemoteFile(byte[] bytes, long offset, File file) {
        if (bytes == null || bytes.length == 0) {
            throw new RuntimeException("bytes is empty");
        }
        log.info("filename{}, length{}, offset{}", file.getName(), bytes.length, offset);
        RandomAccessFile accessTmpFile = null;
        try {
            accessTmpFile = new RandomAccessFile(file, "rw");
            //定位到该分片的偏移量
            accessTmpFile.seek(offset);
            //写入该分片数据
            accessTmpFile.write(bytes);
        } catch (Exception e) {
            log.error("" + e);
            throw new RuntimeException("merge remote file error, location " + offset);
        } finally {
            try {
                accessTmpFile.close();
            } catch (IOException e) {
                log.error("" + e);
                log.error("close randomAccessFile error");
            }
        }
    }

    public static File createFile(String filePath) {
        String dirPath = getFileDir(filePath);
        mkdirs(dirPath);
        return new File(filePath);
    }

    public static void deleteFileAndDir(String filePath) throws FileNotFoundException {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new FileNotFoundException(filePath + " file not exists");
        }
        if (file.isFile()) {
            log.info("delete file{}, result{}",file.getAbsolutePath(), file.delete());
        } else {
            for (File f : file.listFiles()) {
                deleteFileAndDir(f.getAbsolutePath());
            }
            // 删除文件目录
            log.info("delete dir{}, result{}", file.getAbsolutePath(), file.delete());
        }
    }

    /**
     * main
     * @param args
     */
    public static void main(String[] args) throws IOException {
        String sourcePath = "E:\\Github\\fileservice\\src\\main\\java\\com\\scd\\filesdk\\engine\\BaseEngine.java";
        String targetPath = "BaseEngine";
        String basePath = "C:\\Users\\chengdu\\Desktop\\filetype";
        List<String> filePaths = new ArrayList<>(10);
        getFilePaths(basePath, filePaths);
        log.info("" + filePaths);
        log.info("" + System.currentTimeMillis());
        String key = String.format(FileConstants.FILE_INFO, "2434");
        log.info(key);
        String remotePath = "aaaaaa.excel_tmp";
        remotePath = remotePath.substring(0, (remotePath.length() - "_tmp".length()));
        log.info(remotePath);
        String ss = "0101001";
        byte[] ssArr = ss.getBytes();
        for (int i = 0; i < ssArr.length; i++) {
            if (ssArr[i] == 48) {
                log.info("" + i);
            }
        }
    }
}
